/**
 * @file DatabaseError.h
 * @brief 定义数据库错误处理相关的类和函数
 * 
 * 本文件包含数据库操作中可能出现的各种错误类型的定义，
 * 以及用于抛出和处理这些错误的工具函数。
 * 
 * @author 数据库库开发团队
 * @version 1.0
 * @date 2023-07-15
 */

#pragma once

#include <stdexcept>
#include <string>
#include <Poco/Exception.h>
#include "../CLink_Export.h"

namespace CLink 
{
namespace Db 
{

/**
 * @enum DatabaseErrorCode
 * @brief 数据库错误代码枚举
 * 
 * 定义了数据库操作中可能出现的各种错误类型
 */
enum class DatabaseErrorCode {
    NONE = 0,            ///< 无错误
    CONNECTION_FAILED,   ///< 数据库连接失败
    QUERY_FAILED,        ///< 查询执行失败
    TRANSACTION_FAILED,  ///< 事务执行失败
    POOL_EXHAUSTED,      ///< 连接池资源耗尽
    INVALID_PARAMETER,   ///< 无效的参数
    UNSUPPORTED_DATABASE_TYPE, ///< 不支持的数据库类型
    UNKNOWN_ERROR        ///< 未知错误
};

/**
 * @class DatabaseException
 * @brief 数据库异常基类
 * 
 * 所有数据库相关异常的基类，继承自std::runtime_error。
 * 提供了获取错误代码的功能。
 * 
 * @see DatabaseErrorCode
 * 
 * 使用示例：
 * @code
 * try {
 *     // 数据库操作
 * } catch (const DatabaseException& e) {
 *     std::cerr << "错误信息: " << e.what() << std::endl;
 *     std::cerr << "错误代码: " << static_cast<int>(e.getErrorCode()) << std::endl;
 * }
 * @endcode
 */
class CLINK_CLASS DatabaseException : public std::runtime_error {
public:
    DatabaseException(const std::string& message, DatabaseErrorCode code)
        : std::runtime_error(message), _errorCode(code) {}

    DatabaseErrorCode getErrorCode() const { return _errorCode; }

private:
    DatabaseErrorCode _errorCode;
};

/**
 * @class ConnectionException
 * @brief 数据库连接异常类
 * 
 * 当数据库连接出现问题时抛出此异常，如：
 * - 无法连接到数据库服务器
 * - 认证失败
 * - 网络连接中断
 * 
 * @see DatabaseException
 */
class CLINK_CLASS ConnectionException : public DatabaseException {
public:
    /**
     * @brief 构造函数
     * @param message 连接错误的具体描述信息
     */
    ConnectionException(const std::string& message)
        : DatabaseException(message, DatabaseErrorCode::CONNECTION_FAILED) {}
};

/**
 * @class QueryException
 * @brief 数据库查询异常类
 * 
 * 当SQL查询执行出现问题时抛出此异常，如：
 * - SQL语法错误
 * - 表或字段不存在
 * - 数据类型不匹配
 * - 违反约束条件
 * 
 * @see DatabaseException
 */
class CLINK_CLASS QueryException : public DatabaseException {
public:
    /**
     * @brief 构造函数
     * @param message 查询错误的具体描述信息
     */
    QueryException(const std::string& message)
        : DatabaseException(message, DatabaseErrorCode::QUERY_FAILED) {}
};

/**
 * @class TransactionException
 * @brief 数据库事务异常类
 * 
 * 当事务处理出现问题时抛出此异常，如：
 * - 事务提交失败
 * - 事务回滚失败
 * - 死锁检测
 * - 事务超时
 * 
 * @see DatabaseException
 */
class CLINK_CLASS TransactionException : public DatabaseException {
public:
    /**
     * @brief 构造函数
     * @param message 事务错误的具体描述信息
     */
    TransactionException(const std::string& message)
        : DatabaseException(message, DatabaseErrorCode::TRANSACTION_FAILED) {}
};

/**
 * @class PoolException
 * @brief 数据库连接池异常类
 * 
 * 当连接池操作出现问题时抛出此异常，如：
 * - 连接池资源耗尽
 * - 连接获取超时
 * - 连接池配置错误
 * 
 * @see DatabaseException
 */
class CLINK_CLASS PoolException : public DatabaseException {
public:
    /**
     * @brief 构造函数
     * @param message 连接池错误的具体描述信息
     */
    PoolException(const std::string& message)
        : DatabaseException(message, DatabaseErrorCode::POOL_EXHAUSTED) {}
};

/**
 * @brief 错误处理工具函数
 * @{
 */
/**
 * @brief 根据条件抛出数据库异常
 * 
 * 当指定条件为true时，抛出带有指定错误码的数据库异常。
 * 这是一个通用的错误检查工具函数，用于简化错误处理代码。
 * 
 * @param condition 触发异常的条件
 * @param message 异常信息
 * @param code 错误代码
 * @throws DatabaseException 当condition为true时抛出
 * 
 * @code
 * // 使用示例
 * throwIfError(connection == nullptr, "数据库连接失败", DatabaseErrorCode::CONNECTION_FAILED);
 * throwIfError(result < 0, "查询执行失败", DatabaseErrorCode::QUERY_FAILED);
 * @endcode
 */
CLINK_FUNCTION inline void throwIfError(bool condition, const std::string& message, DatabaseErrorCode code) {
    if (condition) {
        throw DatabaseException(message, code);
    }
}

/**
 * @brief 检查空指针并抛出异常
 * 
 * 当指针为nullptr时，抛出带有INVALID_PARAMETER错误码的数据库异常。
 * 这是一个用于指针有效性检查的工具函数。
 * 
 * @param ptr 要检查的指针
 * @param message 异常信息
 * @throws DatabaseException 当ptr为nullptr时抛出，错误码为INVALID_PARAMETER
 * 
 * @code
 * // 使用示例
 * Connection* conn = getConnection();
 * throwIfNull(conn, "无法获取数据库连接");
 * 
 * ResultSet* results = executeQuery(query);
 * throwIfNull(results, "查询结果为空");
 * @endcode
 */
inline void throwIfNull(const void* ptr, const std::string& message) {
    if (ptr == nullptr) {
        throw DatabaseException(message, DatabaseErrorCode::INVALID_PARAMETER);
    }
}

} // namespace db
} // namespace CLink